﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

using AimGameLibrary;
using AimGameLibrary.GameObject;

namespace AimGameEngine.EditorObject
{
    public class CallBack
    {
        public virtual void Deactivate(object sender, EventArgs e)
        {

        }
    }

    public enum SaveMode
    {
        Project,
        Generator
    }

    public class NodeObject : Image2D, ICloneable
    {
        #region System
        protected SpriteFont Font;
        protected Texture2D backupTextureConnectpoint;
        protected float FontDepth;
        public Rectangle NodeBody;
        public String Name;
        #endregion

        #region System List,Dictionary
        protected List<IDraw> MyListDraw;
        protected List<IUpdateMainTime> MyListUpdateTime;
        protected Dictionary<String, NodeObject> MyDictionaryObject;
        protected Dictionary<String, NodeObject> MyDictionaryType;

        public List<Connecter> ListConnectpoint;
        public List<Connecter> ListConnectpointInput;
        public List<Connecter> ListConnectpointOutput;
        public List<LinkLine> LinklinetoConnecter;
        public List<LinkLine> LinklineInputForSave;
        #endregion

        public NodeObject(SpriteBatch inputspritebatch, Camera inputcamera, NodeData MyData
            , List<IDraw> MyListDraw, List<IUpdateMainTime> MyListUpdateTime, Dictionary<String, NodeObject> MyListObject, Dictionary<String, NodeObject> MyListType)
            : base(inputspritebatch, inputcamera)
        {
            this.MyData = MyData.Copy();
            MyViewData.Name = MyData.MyName;

            MyData.Data = "NULL";

            InputMode = NodeInputMode.None;

            //SetupDepth = MyViewData.Depth;

            ListConnectpoint = new List<Connecter>();
            ListConnectpointInput = new List<Connecter>();
            ListConnectpointOutput = new List<Connecter>();
            LinklinetoConnecter = new List<LinkLine>();
            LinklineInputForSave = new List<LinkLine>();

            this.MyListUpdateTime = MyListUpdateTime;
            this.MyListDraw = MyListDraw;
            this.MyDictionaryObject = MyListObject;
            this.MyDictionaryType = MyListType;
        }

        #region Add & Remove Node

        public void AddMetoList()
        {
            MyListUpdateTime.Add(this);
            MyListDraw.Add(this);


            MyDictionaryObject.Add(MyData.MyName, this);

            if (MyDictionaryType != null)
                MyDictionaryType.Add(MyData.MyName, this);

            foreach (IDraw connecter in ListConnectpoint)
                MyListDraw.Add(connecter);

            foreach (IUpdateMainTime connecter in ListConnectpoint)
                MyListUpdateTime.Add(connecter);

            foreach (Connecter connecter in ListConnectpoint)
                if (connecter.MySyco == Syco.Input)
                    ListConnectpointInput.Add(connecter);
                else
                    ListConnectpointOutput.Add(connecter);
            SetupDepth();
        }

        public virtual void Remove()
        {
            MyListDraw.Remove(this);
            MyDictionaryObject.Remove(MyData.MyName);

            if (MyDictionaryType != null)
                MyDictionaryType.Remove(MyData.MyName);

            /// Will Chack Line to Remove
            if (ListConnectpoint != null)
            {
                foreach (IDraw connecter in ListConnectpoint)
                    MyListDraw.Remove(connecter);

                foreach (IUpdateMainTime connecter in ListConnectpoint)
                    MyListUpdateTime.Remove(connecter);

                //ListConnectpoint.Clear();
            }

            if (LinklinetoConnecter.Count > 0)
                foreach (LinkLine Link in LinklinetoConnecter)
                    Link.Isconnect = false;

            ListConnectpointInput.Clear();
            ListConnectpointOutput.Clear();
            LinklinetoConnecter.Clear();
            LinklineInputForSave.Clear();
        }

        #endregion

        #region Sava & Load Data

        public virtual void SaveData(ArrayList Thislist, SaveMode inputsavemode)
        {
            Thislist.Add(MyData);

            if (inputsavemode == SaveMode.Project)
            {
                Thislist.Add(MyViewData.Name);
                Point temp;
                temp.X = (int)MyViewData.Position.X;
                temp.Y = (int)MyViewData.Position.Y;
                Thislist.Add(temp);
            }
        }

        public virtual void LoadData(Identification getdata, int IndexData)
        {

        }

        public Dictionary<String, NodeObject> GetPartNode()
        {
            Dictionary<String, NodeObject> TempNode = new Dictionary<string, NodeObject>();

            TempNode = GetDictionaryNode(TempNode);

            return TempNode;
        }

        protected virtual Dictionary<String, NodeObject> GetDictionaryNode(Dictionary<String, NodeObject> TempNode)
        {
            return TempNode;
        }

        public virtual String CreateData(Dictionary<String, NodeObject> DictionaryObject)
        {
            String TempPacketName = String.Empty;
            int Tempcount = 0;

            foreach (String key0 in DictionaryObject.Keys)
            {
                if (Tempcount > 0)
                    TempPacketName += "|";
                //TempPacketName += DictionaryObjectUpdateIsdown[key0].MyData.MyName;
                TempPacketName += key0;
                Tempcount++;
            }

            return TempPacketName;
        }

        #endregion

        #region Setup Interface
        public virtual void Setup(Texture2D inputTexture, SpriteFont inputFont)
        {
            this.SetupSourceAndTexture(inputTexture);
            Font = inputFont;
            this.NodeBody = MyViewData.Source;
        }

        public virtual void Setup(Texture2D inputTexture, Texture2D inputTexturePoint, SpriteFont inputFont)
        {
            this.SetupSourceAndTexture(inputTexture);
            Font = inputFont;
            this.NodeBody = MyViewData.Source;
            //
            foreach (Connecter connect in ListConnectpoint)
                connect.SetupSourceAndTexture(inputTexturePoint);
            backupTextureConnectpoint = inputTexturePoint;
        }

        public virtual void Setup(Texture2D inputTexture, Texture2D inputTexturePoint, Texture2D outputTexturePoint, SpriteFont inputFont)
        {
            this.SetupSourceAndTexture(inputTexture);
            Font = inputFont;
            this.NodeBody = MyViewData.Source;
            //
            foreach (Connecter connect in ListConnectpoint)
                if (connect.MySyco == Syco.Input)
                    connect.SetupSourceAndTexture(inputTexturePoint);
                else if (connect.MySyco == Syco.Output)
                    connect.SetupSourceAndTexture(outputTexturePoint);

            backupTextureConnectpoint = inputTexturePoint;
        }

        void SetupDepth()
        {
            // Setup Follow AddMetoList()
            MyViewData.Depth = (float)MyListDraw.Count / 1000f;
            foreach (Connecter connecter in ListConnectpoint)
                connecter.MyViewData.Depth = MyViewData.Depth;
        }

        #endregion

        #region System
        protected override void SubDraw()
        {
            base.SubDraw();
            #region Draw Font
            if (Font != null)
                this.spritebatch.DrawString(
                    this.Font
                    , MyViewData.Name
                    , this.camera.ApplyPosition(this) + new Vector2(3, 3)
                    , Color.Black
                    , MyViewData.Rotation
                    , MyViewData.Origin
                    , MyViewData.Scale
                    , MyViewData.Spriteeffects
                    , MyViewData.Depth - 0.001f);
            #endregion
        }

        public override void UpdateTime(TimeSpan timespan)
        {
            base.UpdateTime(timespan);
            NodeBody = new Rectangle((int)this.camera.ApplyPosition(this).X, (int)this.camera.ApplyPosition(this).Y, NodeBody.Width, NodeBody.Height);
        }
        #endregion

        #region SetupInput and Clear Input Node

        public virtual void SetupInput(Connecter Thisconnect, Connecter connectOutput)
        {

        }

        public virtual void ClearInput(Connecter ThisInputConnect, Connecter ThisConnectClear, String NameThisClear)
        {

        }

        #endregion

        #region Setup Proprety Node and Recheck Connecter

        public virtual void ShowProprety(ArrayList Temp, CallBack input)
        {
            Temp.Clear();
            SaveData(Temp, SaveMode.Project);
        }

        public virtual void SetupProprety()
        {
            /// Clean ListOutput and Draw
            foreach (Connecter connect in ListConnectpointInput)
            {
                this.MyListDraw.Remove(connect);
                this.MyListUpdateTime.Remove(connect);
                this.ListConnectpoint.Remove(connect);
            }
            ListConnectpointInput = new List<Connecter>();

            foreach (LinkLine link in this.LinklinetoConnecter)
                link.Isconnect = false;
            /// New obj and add
        }

        protected void AfterSetupProprety()
        {
            foreach (Connecter connecter in ListConnectpoint)
                if (connecter.MySyco == Syco.Input)
                {
                    connecter.SetupSourceAndTexture(backupTextureConnectpoint);
                    ListConnectpointInput.Add(connecter);
                    MyListDraw.Add(connecter);
                    MyListUpdateTime.Add(connecter);
                }
        }

        public void Rename()
        {
            PropretyRename rename = new PropretyRename(this);
            rename.ShowDialog();
        }

        public virtual void ClearConnecter()
        {
            ListConnectpoint.Clear();
            ListConnectpointInput.Clear();
            ListConnectpointOutput.Clear();
        }

        #endregion

        #region ICloneable Members

        public object Clone()
        {
            return this.MemberwiseClone();
        }

        public NodeObject Copy()
        {
            return (NodeObject)this.Clone();
        }

        #endregion
    }
}
